#include <iostream>
#include "Bloque.h"
using namespace std;

Bloque::Bloque(int **m, int nFilas, int nColumnas, int subbanda){

    alto = nFilas;
    ancho = nColumnas;
    banda = subbanda;

    matrix = new int*[alto];
    for (int i = 0 ; i < alto ; i++)
      matrix[i] = new int[ancho];

    //Copia la matriz pasada
    for (int i = 0; i < alto; i++)
        for (int j = 0; j < ancho; j++)
            matrix[i][j] = m[i][j];

    mascaraVecinos = new bool*[alto];
    for (int i = 0 ; i < alto ; i++)
      mascaraVecinos[i] = new bool[ancho];

    mascaraSignificativos = new bool*[alto];
    for (int i = 0 ; i < alto ; i++)
      mascaraSignificativos[i] = new bool[ancho];

    mascaraRefinados = new bool*[alto];
    for (int i = 0 ; i < alto ; i++)
      mascaraRefinados[i] = new bool[ancho];

	inicializaMascaras();
}

void Bloque::inicializaMascaras(){
	for(int i = 0; i < alto; i++){
		for(int j = 0; j < ancho; j++){
			mascaraVecinos[i][j] = false;
			mascaraSignificativos[i][j] = false;
			mascaraRefinados[i][j] = false;
		}
	}
}

void Bloque::anyadeVecinos(int i, int j){
    if(i > 0){
        // mascaraVecinos[i-1][j] = true;
         if(j > 0) mascaraVecinos[i-1][j-1] = true;
         if(j < ancho-1) mascaraVecinos[i-1][j+1] = true;
    }
    if(j > 0){
        mascaraVecinos[i][j-1] = true;
        if(i < alto-1)mascaraVecinos[i][j-1] = true;
    }
    if(j < ancho -1){
        mascaraVecinos[i][j+1] = true;
        if(i < alto-1) mascaraVecinos[i+1][j+1] = true;
    }
    if(i < alto-1) mascaraVecinos[i+1][j] = true;

}

bool Bloque::miraVecinos(int i, int j){
    if(i > 0){
         if(mascaraSignificativos[i-1][j]) return true;
         if(j > 0)
            if(mascaraSignificativos[i-1][j-1]) return true;
         if(j < ancho-1)
            if(mascaraSignificativos[i-1][j+1]) return true;
    }
    if(j > 0){
        if(mascaraSignificativos[i][j-1]) return true;
        if(i < alto-1)
            if(mascaraSignificativos[i+1][j-1]) return true;
    }
    if(j < ancho -1){
        if(mascaraSignificativos[i][j+1]) return true;
        if(i < alto-1)
            if(mascaraSignificativos[i+1][j+1]) return true;
    }
    if(i < alto-1)
        if(mascaraSignificativos[i+1][j]) return true;
    return false;
}



int Bloque::getContextoZC(int i, int j){
    int V = 0, H = 0, D = 0;

    if(i > 0){
        if(mascaraSignificativos[i-1][j]) V++;
        if(j > 0)
            if(mascaraSignificativos[i-1][j-1]) D++;
        if(j < ancho-1)
            if(mascaraSignificativos[i-1][j+1]) D++;
    }
    if(j > 0){
        if(mascaraSignificativos[i][j-1]) H++;
        if(i < alto-1)
            if(mascaraSignificativos[i+1][j-1]) D++;
    }
    if(j < ancho -1){
        if(mascaraSignificativos[i][j+1]) H++;
        if(i < alto-1)
            if(mascaraSignificativos[i+1][j+1]) D++;
    }
    if(i < alto-1)
        if(mascaraSignificativos[i+1][j]) V++;

    if(banda == LL || banda ==LH){
        if(H == 2) return ZC8;
        else if(H == 1 && V >= 1) return ZC7;
        else if(H == 1 && V == 0 && D >= 1) return ZC6;
        else if(H == 1 && V == 0 && D == 0) return ZC5;
        else if(H == 0 && V == 2) return ZC4;
        else if(H == 0 && V == 1) return ZC3;
        else if(H == 0 && V == 0 && D >= 2) return ZC2;
        else if(H == 0 && V == 0 && D == 1) return ZC1;
        else if(H == 0 && V == 0 && D == 0) return ZC0;
    }
    else if(banda == HL){
        if(V == 2) return ZC8;
        else if(V == 1 && H >= 1) return ZC7;
        else if(V == 1 && H == 0 && D >= 1) return ZC6;
        else if(V == 1 && H == 0 && D == 0) return ZC5;
        else if(V == 0 && H == 2) return ZC4;
        else if(V == 0 && H == 1) return ZC3;
        else if(V == 0 && H == 0 && D >= 2) return ZC2;
        else if(V == 0 && H == 0 && D == 1) return ZC1;
        else if(V == 0 && H == 0 && D == 0) return ZC0;
    }
    else {
        if(D >= 3) return ZC8;
        else if(D == 2 && (H+V) >= 1) return ZC7;
        else if(D == 2 && (H+V) == 0) return ZC6;
        else if(D == 1 && (H+V) >= 2) return ZC5;
        else if(D == 1 && (H+V) == 1) return ZC4;
        else if(D == 1 && (H+V) == 0) return ZC3;
        else if(D == 0 && (H+V) >= 2) return ZC2;
        else if(D == 0 && (H+V) == 1) return ZC1;
        else if(D == 0 && (H+V) == 0) return ZC0;
    }


}

void Bloque::contextoSP(int i, int j){
    //contexto.push_back(7);
    int H = 0, V = 0;
    if( j > 0 && j < ancho-1){
        if(mascaraSignificativos[i][j+1] && mascaraSignificativos[i][j-1] && matrix[i][j+1]>0 && matrix[i][j-1]>0)  H = 1;
        else if (mascaraSignificativos[i][j+1] && mascaraSignificativos[i][j-1] && matrix[i][j+1]<0 && matrix[i][j-1]<0)    H = -1;
    }else H = 0;

    if( i > 0 && i < alto-1){
        if(mascaraSignificativos[i+1][j] && mascaraSignificativos[i-1][j] && matrix[i+1][j]>0 && matrix[i-1][j]>0)  V = 1;
        else if(mascaraSignificativos[i+1][j] && mascaraSignificativos[i-1][j] && matrix[i+1][j]<0 && matrix[i-1][j]<0)  V = -1;
    }else V = 0;

    if(V==1 && H ==1){
        contexto.push_back(SC4);
        if(matrix[i][j] >= 0) bits.push_back(0);
        else bits.push_back(1);
    }
    else if(V==-1 && H ==-1){
        contexto.push_back(SC4);
        if(matrix[i][j] < 0) bits.push_back(0);
        else bits.push_back(1);
    }
    else if(V==0 && H ==1) {
        contexto.push_back(SC3);
        if(matrix[i][j] >= 0) bits.push_back(0);
        else bits.push_back(1);
    }
    else if (V==0 && H ==-1){
        contexto.push_back(SC3);
        if(matrix[i][j] < 0) bits.push_back(0);
        else bits.push_back(1);
    }
    else if(V==-1 && H ==1){
        contexto.push_back(SC2);
        if(matrix[i][j] >= 0) bits.push_back(0);
        else bits.push_back(1);
    }
    else if(V==1 && H ==-1){
        contexto.push_back(SC2);
        if(matrix[i][j] < 0) bits.push_back(0);
        else bits.push_back(1);
    }
    else if(V==1 && H ==0){
        contexto.push_back(SC1);
        if(matrix[i][j] >= 0) bits.push_back(0);
        else bits.push_back(1);

    }
    else if(V==-1 && H ==0){
        contexto.push_back(SC1);
        if(matrix[i][j] < 0) bits.push_back(0);
        else bits.push_back(1);

    }
    else{
        contexto.push_back(SC0);
        if(matrix[i][j] >= 0) bits.push_back(0);
        else bits.push_back(1);
    }
}

int Bloque::getContextoMR(int i, int j){
    if(mascaraRefinados[i][j]) return MR2;
    else{
        if(miraVecinos(i,j)) return MR1;
        else return MR0;
    }
}

bool Bloque::getBit(int i, int j, int bitplane){
    char coef = matrix[i][j];
    switch (bitplane){
        case 0:
            return coef & 0x01;
            break;
        case 1:
            return coef & 0x02;
            break;
        case 2:
            return coef & 0x04;
            break;
        case 3:
            return coef & 0x08;
            break;
        case 4:
            return coef & 0x10;
            break;
        case 5:
            return coef & 0x20;
            break;
        case 6:
            return coef & 0x40;
            break;
        case 7:
            return coef & 0x80;
            break;
    }

}
